# +----------------------------------------------------------------------
# | ChatWork智能聊天办公系统
# +----------------------------------------------------------------------
# | 软件声明: 本系统并非自由软件,未经授权任何形式的商业使用均属非法。
# | 版权保护: 任何企业和个人不允许对程序代码以任何形式任何目的复制/分发。
# | 授权要求: 如有商业使用需求,请务必先与版权所有者取得联系并获得正式授权。
# +----------------------------------------------------------------------
# | Author: ChatWork Team <2474369941@qq.com>
# +----------------------------------------------------------------------
import json
from typing import Dict, List
from tortoise.functions import Sum
from kernels.utils import RequestUtil
from config import get_settings
from common.utils.urls import UrlUtil
from common.utils.times import TimeUtil
from common.utils.config import ConfigUtil
from common.enums.models import ModelsEnum
from common.models.dev import DevModelsModel
from common.models.users import UserModel
from common.models.users import UserVisitorModel
from common.models.market import RechargeOrderModel
from common.models.market import SubscribeOrderModel
from common.models.agents import AgentRobotModel
from common.models.agents import AgentKnowModel
from apps.admin.schemas import common_schema as schema
from apps.admin.config import AdminConfig


class IndexService:
    """ 公共服务类 """

    @classmethod
    async def models(cls) -> Dict[str, list]:
        """
        获取模型

        Returns:
            Dict[str, list]: 模型列表Vo

        Author:
            zero
        """
        chat_models = []
        vector_models = []
        ranking_models = []

        for scene in [ModelsEnum.TYPE_CHAT, ModelsEnum.TYPE_VECTOR, ModelsEnum.TYPE_RANKING]:
            lists = await (DevModelsModel
                           .filter(is_disable=0, is_delete=0)
                           .filter(scene=scene)
                           .order_by("sort", "-id")
                           .all())

            for item in lists:
                config = []
                if scene == ModelsEnum.TYPE_CHAT:
                    config = ModelsEnum.chat_models()[item.channel]["configs"][0]["config"]

                _itemVo = schema.AiModelsVo(
                    mark=str(item.mark),
                    name=item.name,
                    logo=await UrlUtil.to_absolute_url(item.logo),
                    config=config,
                    models=[]
                )

                _models = json.loads(item.models)
                for llm in _models:
                    if llm["status"]:
                        _itemVo.models.append(schema.AiModelsVo.Llm(
                            model=llm["model"],
                            alias=str(llm["alias"]),
                            price=int(llm.get("price", 0)),
                            modal=bool(int(llm.get("modal", 0))),
                            max_tokens=int(llm.get("max_tokens", 0)),
                        ))

                if len(_itemVo.models) <= 0:
                    continue

                if scene == ModelsEnum.TYPE_CHAT:
                    chat_models.append(_itemVo)
                elif scene == ModelsEnum.TYPE_VECTOR:
                    vector_models.append(_itemVo)
                elif scene == ModelsEnum.TYPE_RANKING:
                    ranking_models.append(_itemVo)

        return {
            "chat_models": chat_models,
            "vector_models": vector_models,
            "ranking_models": ranking_models
        }

    @classmethod
    async def config(cls) -> schema.SysConfigVo:
        """
        全局配置。

        Returns:
            schema.SysConfigVo: 全局配置Vo。

        Author:
            zero
        """
        pc_conf = await ConfigUtil.get("pc") or {}
        backs_conf = await ConfigUtil.get("backs") or {}
        website_conf = await ConfigUtil.get("website") or {}
        return schema.SysConfigVo(
            name=backs_conf.get("name", ""),
            title=backs_conf.get("title", ""),
            copyright=website_conf.get("copyright", ""),
            cover=await UrlUtil.to_absolute_url(backs_conf.get("cover", "")),
            favicon=await UrlUtil.to_absolute_url(backs_conf.get("favicon", "")),
            pc_logo=await UrlUtil.to_absolute_url(pc_conf.get("logo", "")),
            logo_black_big=await UrlUtil.to_absolute_url(backs_conf.get("logo_black_big", "")),
            logo_black_small=await UrlUtil.to_absolute_url(backs_conf.get("logo_black_small", "")),
            logo_white_big=await UrlUtil.to_absolute_url(backs_conf.get("logo_white_big", "")),
            logo_white_small=await UrlUtil.to_absolute_url(backs_conf.get("logo_white_small", "")),
            enable_captcha=AdminConfig.enable_captcha,
            env_deter=get_settings().ENV_DETER,
            oss_domain=await UrlUtil.get_storage_domain()
        )

    @classmethod
    async def workbench(cls) -> schema.WorkbenchVo:
        """
        控制台数据。

        Returns:
            schema.WorkbenchVo: 控制台数据Vo。

        Author:
            zero
        """
        # 趋势图
        visitor_list = []
        visitor_date = TimeUtil.near_to_date()
        for d in visitor_date:
            start_time: int = TimeUtil.date_to_timestamp(d, "%Y-%m-%d")
            end_time: int = start_time + 86400 - 1
            count: int = await UserVisitorModel.filter(create_time__gte=start_time, create_time__lte=end_time).count()
            visitor_list.append(count)

        # 饼状图
        ua_data = []
        for ua in ["chrome", "firefox", "ie", "safari", "wechat", "other"]:
            count: int = await UserVisitorModel.filter(
                create_time__gte=TimeUtil.today()[0],
                create_time__lte=TimeUtil.today()[1],
                ua=ua
            ).count()
            ua_data.append({"value": count, "name": ua.capitalize()})

        # 每日统计
        daily = await cls._daily_statistics()

        # 数量统计
        totalSum = await cls._sum_statistics()

        # 返回结果
        return schema.WorkbenchVo(
            version={
                "version": get_settings().VERSION,
                "frame": "Fastapi + Vue3 + TypeScript",
                "tones": RequestUtil.licVersion,
                "official": "https://www.mddai.cn/product.html"
            },
            today=[
                {
                    "name": "日增访问",
                    "icon": await UrlUtil.to_absolute_url("static/images/gather_001.png"),
                    "value": daily["visitor"][0],
                    "yesterday": daily["visitor"][1]
                },
                {
                    "name": "日增用户",
                    "icon": await UrlUtil.to_absolute_url("static/images/gather_002.png"),
                    "value": daily["user"][0],
                    "yesterday": daily["user"][1]
                },
                {
                    "name": "今日充值",
                    "icon": await UrlUtil.to_absolute_url("static/images/gather_003.png"),
                    "value": daily["recharge"][0],
                    "yesterday": daily["recharge"][1]
                },
                {
                    "name": "今日订阅",
                    "icon": await UrlUtil.to_absolute_url("static/images/gather_004.png"),
                    "value": daily["subscribe"][0],
                    "yesterday": daily["subscribe"][1]
                }
            ],
            shortcut=[
                {"name": "内容", "icon": "el-icon-Tickets", "path": "/content/article"},
                {"name": "附件", "icon": "el-icon-Files", "path": "/system/materials"},
                {"name": "管理", "icon": "el-icon-Odometer", "path": "/auth/admin"},
                {"name": "菜单", "icon": "el-icon-SuitcaseLine", "path": "/auth/menu"},
                {"name": "任务", "icon": "el-icon-Box", "path": "/system/crontab"},
                {"name": "日志", "icon": "el-icon-Grape", "path": "/system/journal"},
                {"name": "缓存", "icon": "el-icon-Notification", "path": "/system/clear"},
                {"name": "设置", "icon": "el-icon-Setting", "path": "/setting/basics"},
            ],
            backlogs=[
                {"name": "智能体数量", "value": totalSum["robot"], "path": ""},
                {"name": "知识库数量", "value": totalSum["know"], "path": ""},
                {"name": "充值订单数", "value": totalSum["recharge"], "path": ""},
                {"name": "订阅会员数", "value": totalSum["subscribe"], "path": ""}
            ],
            echartsVisitor={
                "date": visitor_date,
                "list": visitor_list
            },
            echartsWebsite=ua_data
        )

    @classmethod
    async def _daily_statistics(cls) -> Dict[str, List[int]]:
        """
        每日统计。

        Returns:
            Dict[str, List[int]]: 统计的数据。

        Author:
            zero
        """
        subscribe_num: List[int] = []
        recharge_num: List[int] = []
        visitor_num: List[int] = []
        user_num: List[int] = []

        for d in [TimeUtil.today(), TimeUtil.yesterday()]:
            # 日增访问
            visitor_num.append(await UserVisitorModel.filter(create_time__gte=d[0], create_time__lte=d[1]).count())

            # 日增用户
            user_num.append(await UserModel.filter(create_time__gte=d[0], create_time__lte=d[1]).count())

            # 日增充值
            recharge = await (RechargeOrderModel
                              .annotate(paid_amount=Sum("paid_amount"))
                              .filter(pay_status=1)
                              .filter(create_time__gte=d[0])
                              .filter(create_time__lte=d[1])
                              .first().values('paid_amount'))
            recharge_num.append(recharge["paid_amount"] or 0)

            # 日增订阅
            subscribe = await (SubscribeOrderModel
                               .annotate(paid_amount=Sum("paid_amount"))
                               .filter(pay_status=1)
                               .filter(create_time__gte=d[0])
                               .filter(create_time__lte=d[1])
                               .first().values('paid_amount'))
            subscribe_num.append(subscribe["paid_amount"] or 0)

        return {
            "subscribe": subscribe_num,
            "recharge": recharge_num,
            "visitor": visitor_num,
            "user": user_num
        }

    @classmethod
    async def _sum_statistics(cls) -> Dict[str, int]:
        """
        数量统计。

        Returns:
            Dict[str, int]: 统计的数据。

        Author:
            zero
        """
        return {
            "know": await AgentKnowModel.filter(is_delete=0).count(),
            "robot": await AgentRobotModel.filter(is_delete=0).count(),
            "recharge": await RechargeOrderModel.filter(pay_status=1).count(),
            "subscribe": await SubscribeOrderModel.filter(pay_status=1).count(),
        }
